#include "common_opr_all.h"
#include "curl/curl.h"
#include "fileReupload.h"
#include "soaAndrEnvir.h"

using namespace DcAdr;

map<string, map<string, string>> mm_subSysDomain;
map<string, uint64_t> m_domainGetTimes;
map<string, string> m_domainVersion;
mutex mutex_subSysDomain;

string global_tokenMsg;
string global_secretKey;
mutex mutex_login;

// 用于环境变量切换时,获取子系统域名和token判断
string oldEnvirVarDomain;
string oldEnvirVarToken;

CommonOprHttp::CommonOprHttp()
{
    domainPort = 0;
}

CommonOprHttp::~CommonOprHttp()
{
}

size_t CommonOprHttp_JSONDataCopy(void *ptr, size_t size, size_t nmemb, void *stream)
{
    ((std::string *)stream)->append((char *)ptr, size * nmemb);
    return size * nmemb;
}

size_t CommonOprHttp_WriteFile(void *contents, size_t size, size_t nmemb, std::ofstream *file)
{
    file->write(static_cast<char *>(contents), size * nmemb);
    return size * nmemb;
}

bool CommonOprHttp::getDomainHostPort(string udsDomainUrl, string domainName, string &hostName, int &PortName)
{
    lock_guard<mutex> locker(mutex_subSysDomain);
    bool ret = false;
    Log_Info("[CommonOprHttp] [getDomainHostPort] udsDomainUrl:{} domainName:{}", udsDomainUrl, domainName);

    if(!getSubSysDomain(udsDomainUrl, domainName))
    {
        Log_Info("[CommonOprHttp] [getDomainHostPort] get SubSysDomain failed!");
        return ret;
    }

    map<string, string> &m_domains = mm_subSysDomain[udsDomainUrl];
    if(NotContain_Map(m_domains, domainName))
    {
        Log_Info("[CommonOprHttp] [getDomainHostPort] unknowen domainName in subSysDomain list!");
        return ret;
    }

    string domainValue = m_domains[domainName];
    string strHost = CommonOprString::getbetweenstrs(domainValue, "start", ":");
    string strPort = CommonOprString::getbetweenstrs(domainValue, ":", "end");

    if (domainValue.empty() || strHost.empty() || strPort.empty())
    {
        Log_Info("[CommonOprHttp] [getDomainHostPort] parse domainHost or domainPort failed!");
        return ret;
    }

    hostName = strHost;
    PortName = stoi(strPort);
    Log_Info("[MqttHttpReq] [getDomainHostPort] domainName hostName:{}", hostName);
    Log_Info("[MqttHttpReq] [getDomainHostPort] domainName PortName:{}", PortName);

    ret = true;
    return ret;
}

bool CommonOprHttp::getSubSysDomain(string childUrl, string domainName)
{
    uint64_t &latestGetTime = m_domainGetTimes[childUrl];
    uint64_t curTime = CommonOprTime::getTime();

    if (oldEnvirVarDomain == global_data::g_cloudNetPrefix)
    {
        // 已经获取过子系统域名
        if(Contain_Map(mm_subSysDomain, childUrl) && TimeOneDay > curTime - latestGetTime)
        {
            map<string, string> &m_domains = mm_subSysDomain[childUrl];
            if(Contain_Map(m_domains, domainName))
            {
                return true;
            }
        }
    }
    oldEnvirVarDomain = global_data::g_cloudNetPrefix;

    latestGetTime = curTime;
    std::string url = SRT_HTTPSPRE + global_data::g_cloudNetPrefix + childUrl;

    Log_Info("[http_url][CommonOprHttp] [getSubSysDomain] full req url:{}", url);

    // 设置http请求头
    map<string, string> http_header;
    http_header["Content-Type"] = "application/json;charset=UTF-8";
    http_header["Accept"] = "*/*";
    http_header["X-VCS-Timestamp"] = CommonOprTime::getTimestr();
    http_header["X-VCS-Nonce"] = CommonOprString::GetRandStr(4);

    // 设置请求body
    Json::FastWriter writer;
    Json::Value parampostFiled;
    parampostFiled["tuid"] = CommonOprServser::getTuid();
    // 计算证书特征值
    string certaddstr = http_header["X-VCS-Timestamp"];
    Log_Info("[MqttHttpReq] [GetMqttHost] call GetCertCharVal_MD5x509_Hex");
    parampostFiled["sign"] = CommonOprOpenssl::GetCertCharVal_MD5x509_Hex(certaddstr);
    parampostFiled["version"] = "V2";

    if( DC_SUCC == CommonOprString::childStrContainCheck(childUrl, "uds2") )
    {
        parampostFiled["udsProtoVersion"] = "2.0";
    }
    if( Contain_Map(m_domainVersion, childUrl) )
    {
        parampostFiled["configVersion"] = m_domainVersion[childUrl];
    }

    std::string postFiled = writer.write(parampostFiled);

    std::string responseBuff;
    if (!doHttpPostRequest(url, http_header, postFiled, 0, responseBuff))
    {
        return false;
    }

    Json::Reader reader;
    Json::Value root;
    if ((!reader.parse(responseBuff, root)) || (!root.isMember("data")))
    {
        Log_Info("[CommonOprHttp] [getSubSysDomain] res data check failed, data is not json or param error!");
        return false;
    }

    Json::Value dataJson = root["data"];

    if ( !dataJson.isObject() || dataJson.empty() )
    {
        Log_Info("[CommonOprHttp] [getSubSysDomain] res data check failed, data is not json...");
        return false;
    }

    if ( CommonOprJson::checkMember(dataJson, "configVersion") )
    {
        m_domainVersion[childUrl] = JsonToValue<std::string>(dataJson["configVersion"]);
    }


    map<string, string> &m_domains = mm_subSysDomain[childUrl];
    Json::Value::Members member = dataJson.getMemberNames();
    for(Json::Value::Members::iterator iter = member.begin(); iter != member.end(); ++iter)
    {
        std::string memberName = *iter;
        string doMainValue = JsonToValue<std::string>(dataJson[memberName]);

        if( DC_SUCC == CommonOprString::childStrContainCheck(memberName, "Domain") )
        {
            m_domains[memberName] = doMainValue;
        }
    }

    return true;
}

bool CommonOprHttp::doHttpGetRequest(const string &url, map<string, string> &http_headermap, bool withAuthorization, string &o_resposeBuff)
{
    bool ret = false;
    Log_Info("[CommonOprHttp] [doHttpGetRequest] url:{}", url);

    if( url.empty() )
    {
        Log_Info("[CommonOprCurl] [doHttpGetRequest] ERROR: empty url!");
        return ret;
    }

    // curl初始化
    CURL *curl = curl_easy_init();
    if (curl == nullptr)
    {
        Log_Info("[CommonOprCurl] [doHttpGetRequest] ERROR: curl init failed");
        return ret;
    }

    // 设置method为post,设置请求的URL
    CURLcode retCI = curl_easy_setopt(curl, CURLOPT_POST, 0);
    (void)retCI;
    retCI = curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    retCI = curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
    retCI = curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_MAX_TLSv1_2);
    
    // 设置http请求头
    http_headermap["X-VCS-BusiModule"] = "C2MADR";
    struct curl_slist *http_header = NULL;
    string headerpara = "";
    map<string, string>::reverse_iterator iter;
    for (iter = http_headermap.rbegin(); iter != http_headermap.rend(); iter++)
    {
        headerpara = iter->first;
        headerpara = headerpara + ":" + iter->second;
        http_header = curl_slist_append(http_header, headerpara.c_str());
    }
    // http请求头中生成签名认证信息
    if (withAuthorization)
    {
        headerpara = "Authorization";
        string postfiled;
        string Authorization = GenAuthorization(STR_REQ_GET, url, http_headermap, postfiled);
        headerpara = headerpara + ":" + Authorization;
        http_header = curl_slist_append(http_header, headerpara.c_str());
    }
    retCI = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_header);

    // 设置发送超时时间
    retCI = curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10);
    retCI = curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
    // 设置密钥验证方式
    // 设置密钥验证方式
    retCI = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
    retCI = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
    retCI = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);

    string client_cert_path = global_data::g_http_ca_path + global_data::g_client_cert;
    retCI = curl_easy_setopt(curl, CURLOPT_SSLCERT, client_cert_path.c_str());
    retCI = curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");

    // 填充curl_blob结构
    curl_blob private_key_blob = {
        .data = (void *)global_data::g_client_keyBuff.c_str(),
        .len = global_data::g_client_keyBuff.size(),
        .flags = 0};
    // 设置SSL证书的二进制数据
    retCI = curl_easy_setopt(curl, CURLOPT_SSLKEY_BLOB, private_key_blob);

    // 设置根证书双向认证
    string certPath = global_data::g_SdaCaFilePath;
    string rootCertFile = certPath + global_data::g_rootCaCertPem;
    if (!CommonOprSystem::isPathExist(rootCertFile))
    {
        certPath = global_data::g_httpCaFilePath;
        rootCertFile = certPath + global_data::g_rootCaCertPem;
    }
    retCI = curl_easy_setopt(curl, CURLOPT_CAINFO, rootCertFile.c_str());

    // 设置传输的字符串
    retCI = curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);
    retCI = curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

    // 设置回调函数
    std::string responseBuff;
    retCI = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseBuff);
    retCI = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CommonOprHttp_JSONDataCopy);

    CURLcode res = CURLE_OK;
    (void)res;
#ifdef USE_AARCH64_ANDROID
    res = curl_easy_perform(curl);
    if (res != CURLE_OK)
    {
        Log_Info("[CommonOprCurl] [doHttpGetRequest] Http Error curl response:{}", curl_easy_strerror(res));
    }
    else
#endif
    {
        o_resposeBuff = responseBuff;
        Log_Info("[CommonOprCurl] [doHttpGetRequest] Http success:{}", o_resposeBuff);
        ret = true;
    }

    // 释放内存
    curl_slist_free_all(http_header);
    curl_easy_cleanup(curl);
    return ret;
}

bool CommonOprHttp::doHttpPostRequest(const string &url, map<string, string> &http_headermap, string &postfiled, bool withAuthorization, string &o_resposeBuff)
{
    bool ret = false;
    Log_Info("[CommonOprHttp] [doHttpPostRequest] url:{}", url);

    // 去除json中的换行符，保证云端与车端计算的特征值一致
    CommonOprJson::jsonstrformat(postfiled);
    Log_Info("[CommonOprHttp] [doHttpPostRequest] postfiled:{}", postfiled);

    // curl初始化
    CURL *curl = curl_easy_init();
    if (curl == nullptr)
    {
        Log_Info("[CommonOprCurl] [doHttpPostRequest] ERROR: curl init failed");
        return ret;
    }

    // 设置method为post,设置请求的URL
    CURLcode retCI = curl_easy_setopt(curl, CURLOPT_POST, 1);
    (void)retCI;
    retCI = curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    retCI = curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);

    // 设置http请求头
    http_headermap["X-VCS-BusiModule"] = "C2MADR";
    struct curl_slist *http_header = NULL;
    string headerpara = "";
    map<string, string>::reverse_iterator iter;
    for (iter = http_headermap.rbegin(); iter != http_headermap.rend(); iter++)
    {
        headerpara = iter->first;
        headerpara = headerpara + ":" + iter->second;
        http_header = curl_slist_append(http_header, headerpara.c_str());
        Log_Info("[CommonOprCurl] [doHttpPostRequest] header:{} :{}", iter->first, iter->second);
    }
    // http请求头中生成签名认证信息
    if (withAuthorization)
    {
        headerpara = "Authorization";
        string Authorization = GenAuthorization(STR_REQ_POST, url, http_headermap, postfiled);
        headerpara = headerpara + ":" + Authorization;
        http_header = curl_slist_append(http_header, headerpara.c_str());
        Log_Info("[CommonOprCurl] [] header, Authorization:{}", Authorization);
    }
    retCI = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_header);

    // 设置发送超时时间
    retCI = curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
    // 设置密钥验证方式
    retCI = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
    retCI = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
    retCI = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    // 设置根证书双向认证
    string certPath = global_data::g_SdaCaFilePath;
    string rootCertFile = certPath + global_data::g_rootCaCertPem;
    if (!CommonOprSystem::isPathExist(rootCertFile))
    {
        certPath = global_data::g_httpCaFilePath;
        rootCertFile = certPath + global_data::g_rootCaCertPem;
    }
    retCI = curl_easy_setopt(curl, CURLOPT_CAINFO, rootCertFile.c_str());

    string client_cert_path = global_data::g_http_ca_path + global_data::g_client_cert;
    retCI = curl_easy_setopt(curl, CURLOPT_SSLCERT, client_cert_path.c_str());
    retCI = curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
    // 设置传输的字符串
    retCI = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postfiled.c_str());
    retCI = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, postfiled.size());
    retCI = curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);
    retCI = curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

    // 填充curl_blob结构
    curl_blob private_key_blob = {
        .data = (void *)global_data::g_client_keyBuff.c_str(),
        .len = global_data::g_client_keyBuff.size(),
        .flags = 0};
    // 设置SSL证书的二进制数据
    retCI = curl_easy_setopt(curl, CURLOPT_SSLKEY_BLOB, private_key_blob);

    // 设置回调函数
    std::string responseBuff;
    retCI = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseBuff);
    retCI = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CommonOprHttp_JSONDataCopy);

    CURLcode res = CURLE_OK;

    // 发起请求
    Log_Mqtt("[CommonOprCurl] [doHttpPostRequest] call curl_easy_perform");
    res = curl_easy_perform(curl);
    if (res != CURLE_OK)
    {
        Log_Mqtt("[CommonOprCurl] [doHttpPostRequest] Http Error curl response: {}", curl_easy_strerror(res));
    }
    else
    {
        o_resposeBuff = responseBuff;
        Log_Mqtt("[CommonOprCurl] [doHttpPostRequest] Http success: {}", o_resposeBuff);
        ret = true;
    }

    // 释放内存
    curl_slist_free_all(http_header);
    curl_easy_cleanup(curl);
    return ret;
}

string CommonOprHttp::GenAuthorization(string reqType, const string &url, map<string, string> http_headermap, const string &postfiled)
{

    string CanonicalHeadersEntrys = reqType + "\n";

    string CanonicalURI = CommonOprString::getbetweenstrs(url, ".cn", "?");
    CanonicalHeadersEntrys = CanonicalHeadersEntrys + CanonicalURI + "\n";

    string CanonicalQueryString = CommonOprString::getbetweenstrs(url, "?", "end");
    CanonicalHeadersEntrys = CanonicalHeadersEntrys + CanonicalQueryString + "\n";

    vector<string> signkeys;
    signkeys.push_back("X-VCS-BusiModule");
    signkeys.push_back("X-VCS-Hu-Token");
    signkeys.push_back("X-VCS-Hu-User-Token");
    signkeys.push_back("X-VCS-Nonce");
    signkeys.push_back("X-VCS-Timestamp");

    for (auto signkey : signkeys)
    {
        if (0 == http_headermap.count(signkey))
        {
            continue;
        }
        string signvalue = http_headermap[signkey];
        CommonOprString::strchangelower(signkey);
        CanonicalHeadersEntrys = CanonicalHeadersEntrys + signkey + ":" + signvalue + "\n";
    }
    CanonicalHeadersEntrys = CanonicalHeadersEntrys + "\n";

    // Log_Mqtt("[CommonOprCurl] [GenAuthorization] CanonicalHeadersEntrys:\n {}", CanonicalHeadersEntrys);

    string HashedRequestPayload = CommonOprOpenssl::GetStringSha256HexStr(postfiled);
    CommonOprString::strchangelower(HashedRequestPayload);
    // Log_Mqtt("[CommonOprCurl] [GenAuthorization] strchangelower HashedRequestPayload:\n {}", HashedRequestPayload);

    string CanonicalRequestMethod = CanonicalHeadersEntrys + HashedRequestPayload;
    // Log_Mqtt("[CommonOprCurl] [GenAuthorization] CanonicalRequestMethod:\n {}", CanonicalRequestMethod);

    string HashedCanonicalRequest = CommonOprOpenssl::GetStringSha256HexStr(CanonicalRequestMethod);
    CommonOprString::strchangelower(HashedCanonicalRequest);
    // Log_Mqtt("[CommonOprCurl] [GenAuthorization] HashedCanonicalRequest:\n {}", HashedCanonicalRequest);

    string StringToSign = "VCS-HMAC-SHA256\n";
    StringToSign = StringToSign + http_headermap["X-VCS-Timestamp"] + "\n";
    StringToSign = StringToSign + HashedCanonicalRequest;
    // Log_Mqtt("[CommonOprCurl] [GenAuthorization] StringToSign:\n {}", StringToSign);

    Log_Mqtt("[CommonOprCurl] [GenAuthorization] hu_secretKey:\n {}", hu_secretKey);
    string signature;
    CommonOprOpenssl::HmacEncode_Hex("sha256", hu_secretKey, StringToSign, signature);
    CommonOprString::strchangelower(signature);
    // Log_Mqtt("[CommonOprCurl] [GenAuthorization] signature:\n {}", signature);

    string signAuthorization = "";
    signAuthorization = signAuthorization + "VCS-HMAC-SHA256 Signature=" + signature;
    Log_Mqtt("[CommonOprCurl] [GenAuthorization] signAuthorization:\n {}", signAuthorization);

    return signAuthorization;
}


typedef struct ctl
{
    string filePath;
    curl_off_t size;
    curl_off_t position;
} CTL_S;

size_t read_callback(char *buffer, size_t size, size_t nitems, void *arg)
{
    string data = "";
    CTL_S *p = (CTL_S *)arg;
    curl_off_t sz = p->size - p->position;
    nitems *= size;
    if (sz > nitems)
        sz = nitems;
    if (sz)
    {
        // Log_Info("read_callback, name:"<< p->filePath << "offset:" << p->position << ", size:"<< sz);
        // 从磁盘读取 读取失败返回0退出read上传
        if (DC_FAIL == CommonOprSystem::readFilePartly(p->filePath, p->position, sz, data))
        {
            return 0;
        }
        else
        {
            memcpy(buffer, data.c_str(), MIN(data.size(), sz));
        }
    }
    p->position += sz;
    return sz;
}

int seek_callback(void *arg, curl_off_t offset, int origin)
{
    CTL_S *p = (CTL_S *)arg;
    switch (origin)
    {
    case SEEK_END:
        offset += p->size;
        break;
    case SEEK_CUR:
        offset += p->position;
        break;
    default:
        break;
    }
    if (offset < 0)
    {
        Log_Info("seek_callback error, offset:{}", offset);
        return CURL_SEEKFUNC_FAIL;
    }
    Log_Info("seek_callback, offset:{}", offset);
    p->position = offset;
    return CURL_SEEKFUNC_OK;
}

bool CommonOprHttp::doHttpUploadFile(std::string &o_resposeBuff, const std::string &url_addr, const std::string &fcToken, const std::string &headerMsg, const std::string &filePath, const std::string &headerValue, bool isChunk)
{
    (void)headerValue;
    Log_Mqtt(__FUNCTION__);
    CURL *curl = curl_easy_init();
    struct curl_slist *http_header = NULL;
    if (curl == nullptr)
    {
        Log_Mqtt("ERROR: curl init failed");
        return false;
    }
    http_header = (struct curl_slist *)calloc(1, sizeof(struct curl_slist));
    if (http_header == NULL)
    {
        curl_easy_cleanup(curl);
        return false;
    }
    http_header->next = NULL;

    http_header->data = (char *)headerMsg.c_str();
    Log_Mqtt("headerMsg: {}", headerMsg);

    http_header->next = (struct curl_slist *)calloc(1, sizeof(struct curl_slist));
    if (http_header->next == NULL)
    {
        free(http_header->data);
        free(http_header);
        curl_easy_cleanup(curl);
        return false;
    }

    http_header->next->next = NULL;
    http_header->next->data = strdup("Accept: */*");
    struct curl_slist *pOptionList = NULL;
    (void)pOptionList;
    // 添加HTTP的包头 Expect：防止数据大于1024个字节 需要等待服务响应
    // 也许有Expect: 100-continue，去掉它
    http_header = curl_slist_append(http_header, "Expect:");

    string tmp = "";
    tmp = "X-VCS-Fc-Token:";
    tmp += fcToken;
    // tmp += "9e9a29f0-9439-428a-a32a-56ea21367ed3";
    http_header = curl_slist_append(http_header, tmp.c_str());
    // Log_Mqtt("[HttpCommon] [GenHeadrwithsign] {}", tmp);
    string timstr = CommonOprTime::getTimestr();
    tmp = "X-VCS-Timestamp:";
    tmp += timstr;
    http_header = curl_slist_append(http_header, tmp.c_str());
    // Log_Mqtt("[HttpCommon] [GenHeadrwithsign] {}", tmp);

    string randstr = CommonOprString::GetRandStr(4);
    tmp = "X-VCS-Nonce:";
    tmp += randstr;
    http_header = curl_slist_append(http_header, tmp.c_str());
    // Log_Mqtt("[HttpCommon] [GenHeadrwithsign] {}", tmp);

    CURLcode retCI;
    (void)retCI;
    // 分片文件上传请求参数不包含header
    if (!isChunk)
    {
        retCI = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_header);
    }
    std::string responseBuff;
    retCI = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseBuff);
    retCI = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CommonOprHttp_JSONDataCopy);
    // curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)-1);

#if 0 // old  
    struct curl_httppost *pFormPost = NULL;
    struct curl_httppost *pLastElem = NULL;
    //上传文件，指定本地文件完整路径
    // Log_Mqtt("filePath: {}, base name: {}", filePath, CommonOprSystem::getFileBaseName(filePath).c_str());
    curl_formadd(&pFormPost, &pLastElem, CURLFORM_COPYNAME, CommonOprSystem::getFileBaseName(filePath).c_str(),
                 CURLFORM_FILE, filePath.c_str(),
                 CURLFORM_CONTENTTYPE, headerValue.c_str(), CURLFORM_END);

    retCI = curl_easy_setopt(curl, CURLOPT_HTTPPOST, pFormPost);
    retCI = curl_easy_setopt(curl, CURLOPT_URL, url_addr.c_str());
    retCI = curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);
    retCI = curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);

    /* enable TCP keep-alive for this transfer */
    retCI = curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
    /* keep-alive idle time to 120 seconds */
    retCI = curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);
    /* interval time between keep-alive probes: 60 seconds */
    retCI = curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);

    //设置传输速度下限，60秒内传输速度低于100字节/秒会中止传输
    retCI = curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 100);
    retCI = curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 60);

    //获取上传进度
    // curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
    // curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, filePorgressFunc);

    retCI = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);//生产环境云盘bug，加上规避
    retCI = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);

    CURLcode res = curl_easy_perform(curl);
    if (res != CURLE_OK)
    {
        o_resposeBuff = curl_easy_strerror(res);
        Log_Mqtt("Http Error curl response: {}", curl_easy_strerror(res));
    }
    else
    {
        o_resposeBuff = responseBuff;
        Log_Mqtt("Http success: {}", o_resposeBuff);
    }
    curl_formfree(pFormPost);
    curl_easy_cleanup(curl);
    Log_Mqtt("{} end",__FUNCTION__);
    
    FileReupload::getInstance().dealUploadResult(filePath, (uint32_t)res);

    return res == CURLE_OK;
#endif

    curl_mime *mime = NULL;
    curl_mimepart *mime_part = NULL;

    CTL_S hugectl;
    int datasize = 0;
    CommonOprSystem::queryFileSize(filePath, datasize);
    hugectl.size = datasize;
    hugectl.position = 0;
    hugectl.filePath = filePath;
    mime = curl_mime_init(curl);
    if (mime == NULL)
    {
        Log_Info("curl_mime_init error");
    }
    else
    {
        mime_part = curl_mime_addpart(mime);
    }
    if (mime_part == NULL)
    {
        Log_Info("curl_mime_addpart error");
    }
    else
    {
        retCI = curl_mime_type(mime_part, "application/octet-stream");
        retCI = curl_mime_name(mime_part, "file");
        retCI = curl_mime_filename(mime_part, CommonOprSystem::getFileBaseName(filePath).c_str());
        retCI = curl_mime_data_cb(mime_part, hugectl.size, read_callback, seek_callback, NULL, &hugectl);
        retCI = curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
    }
    Log_Info("filePath:{} base_name:{}", filePath, CommonOprSystem::getFileBaseName(filePath));
    /*
    //采用curl_mime_data_cb接口，支持上传修改的文件
    struct curl_httppost *pFormPost = NULL;
    struct curl_httppost *pLastElem = NULL;
    //上传文件，指定本地文件完整路径
    Log_Info("filePath:" << filePath << "base name:" << CommonOprSystem::getFileBaseName(filePath).c_str());
    curl_formadd(&pFormPost, &pLastElem, CURLFORM_COPYNAME, CommonOprSystem::getFileBaseName(filePath).c_str(),
                 CURLFORM_FILE, filePath.c_str(),
                 CURLFORM_CONTENTTYPE, headerValue.c_str(), CURLFORM_END);

    curl_easy_setopt(curl, CURLOPT_HTTPPOST, pFormPost);
    */

    retCI = curl_easy_setopt(curl, CURLOPT_URL, url_addr.c_str());
    retCI = curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);
    retCI = curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
    retCI = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
    retCI = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
    retCI = curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_MAX_TLSv1_2);

    /* enable TCP keep-alive for this transfer */
    retCI = curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
    /* keep-alive idle time to 120 seconds */
    retCI = curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);
    /* interval time between keep-alive probes: 60 seconds */
    retCI = curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);

    //设置传输速度下限，60秒内传输速度低于100字节/秒会中止传输
    retCI = curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 100);
    retCI = curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 60);

    CURLcode res = CURLE_OK;
    res = curl_easy_perform(curl);

    if (res != CURLE_OK)
    {
        const char * error_msg = curl_easy_strerror(res);
        if (error_msg != NULL)
        {
            o_resposeBuff = error_msg;
            Log_Mqtt("Http Error curl response: {}", o_resposeBuff);
        }
        else
        {
            Log_Mqtt("call  curl_easy_strerror() == NULL");
        }                
    }else
    {
        o_resposeBuff = responseBuff;
        Log_Mqtt("Http success: {}", o_resposeBuff);
    }
    // curl_formfree(pFormPost);
    curl_easy_cleanup(curl);
    curl_mime_free(mime);
    Log_Mqtt("{} end", __FUNCTION__);

    return res == CURLE_OK;
}
bool CommonOprHttp::httpReqInit(string domainName)
{
    bool ret = false;
    string udsDomainUrl = SRT_URL_GETSUBSYSDOMANIN;
    if(!getDomainHostPort(udsDomainUrl, STR_DOMAIN_TUSYS, domainHost, domainPort))
    {
        Log_Info("[CommonOprHttp] [httppReqInit] get SubSysDomain failed!");
        return ret;
    }
    if (!loginGethutocken())
    {
        Log_Info("[CommonOprHttp] [httppReqInit] login and get hutocken failed!");
        return ret;
    }

    if (!getDomainHostPort(udsDomainUrl, domainName, domainHost, domainPort))
    {
        Log_Info("[CommonOprHttp] [httppReqInit] get SubSysDomain failed!");
        return ret;
    }
    ret = true;
    return ret;
}

bool CommonOprHttp::loginGethutocken()
{
    static uint64_t latestTockenGetTime = 0;
    uint64_t curTime = CommonOprTime::getTime();

    if (oldEnvirVarToken == global_data::g_cloudNetPrefix)
    {
        if(5*60*1000 > curTime - latestTockenGetTime)
        {
            lock_guard<mutex> locker(mutex_login);
            hu_tokenMsg = global_tokenMsg;
            hu_secretKey = global_secretKey;
            if( (!hu_tokenMsg.empty()) && (!hu_secretKey.empty()) )
            {
                Log_Info("[CommonOprHttp] [loginGethutocken] noneed update, use global_tokenMsg...");
                return true;
            }
        }
    }
    oldEnvirVarToken = global_data::g_cloudNetPrefix;

    // 更新全局tocken
    if(!updateHuTocken())
    {
        Log_Info("[CommonOprHttp] [loginGethutocken] update global_tokenMsg failed!");
        return false;
    }

    // 更新tocken成功，更新时间记录
    latestTockenGetTime = curTime;
    return true;
}



bool CommonOprHttp::updateHuTocken()
{
    lock_guard<mutex> locker(mutex_login);

    bool ret = false;
    std::string url = SRT_HTTPSPRE + domainHost + SRT_URL_LOGINGETTOCKEN;
    Log_Info("[CommonOprHttp] [updateHuTocken] global tokenMsg update; url:{}", url);

    // 设置http请求头
    map<string, string> http_header;
    http_header["Content-Type"] = "application/json;charset=UTF-8";
    http_header["Accept"] = "*/*";
    http_header["X-VCS-Timestamp"] = CommonOprTime::getTimestr();
    http_header["X-VCS-Nonce"] = CommonOprString::GetRandStr(4);
    
    // 设置请求body
    Json::FastWriter writer;
    Json::Value parampostFiled;
    parampostFiled["tuid"] = CommonOprServser::getTuid();
    // 计算证书特征值
    string certaddstr = http_header["X-VCS-Timestamp"];
    Log_Info("[CommonOprHttp] [loginGethutocken] call GetCertCharVal_MD5x509_Hex");
    parampostFiled["sign"] = CommonOprOpenssl::GetCertCharVal_MD5x509_Hex(certaddstr);
    std::string postFiled = writer.write(parampostFiled);

    // 发起请求
    std::string responseBuff;
    bool httppostret = CommonOprHttp::doHttpPostRequest(url, http_header, postFiled, 0, responseBuff);
    if(!httppostret)
    {
      Log_Info("[CommonOprHttp] [loginGethutocken] do Http Post Request failed!");  
    }

    // 解析请求响应结果
    Json::Reader reader;
    Json::Value root;
    if ((!reader.parse(responseBuff, root)) || (!root.isMember("data")))
    {
        Log_Info("[CommonOprHttp] [loginGethutocken] res data check failed, data is not json or param error!");
        return ret;
    }

    Json::Value dataJson = root["data"];
    if (!dataJson.isObject() || (!dataJson.isMember("huToken")) || (!dataJson.isMember("secretKey")))
    {
        Log_Info("[CommonOprHttp] [loginGethutocken] res data check failed, dataJson is not json or param error!");
        return ret;
    }

    // 保存token与secretKey
    hu_tokenMsg = JsonToValue<std::string>(dataJson["huToken"]);
    hu_secretKey = JsonToValue<std::string>(dataJson["secretKey"]);
    if (hu_tokenMsg.empty() || hu_secretKey.empty())
    {
        Log_Info("[CommonOprHttp] [loginGethutocken] parse hu_tokenMsg or hu_secretKey failed!");
        return ret;
    }

    global_tokenMsg = hu_tokenMsg;
    global_secretKey = hu_secretKey;
    Log_Info("[CommonOprHttp] [loginGethutocken] parse dataJson succ, hu_tokenMsg:{}", global_tokenMsg);
    Log_Info("[CommonOprHttp] [loginGethutocken] parse dataJson succ, hu_secretKey:{}", global_secretKey);
    ret = true;
    return ret;
}

bool CommonOprHttp::getCloudConfig(string addr, map<string, string> &http_headermap, string &o_resposeBuff)
{

    // curl初始化
    CURL *curl = curl_easy_init();
    if (curl == nullptr)
    {
        Log_Mqtt("[CommonOprCurl] [doHttpPostRequest] ERROR: curl init failed");
        return false;
    }

    // 设置http请求头
    struct curl_slist *http_header = NULL;
    string headerpara = "";
    map<string, string>::reverse_iterator iter;
    for (iter = http_headermap.rbegin(); iter != http_headermap.rend(); iter++)
    {
        headerpara = iter->first;
        headerpara = headerpara + ":" + iter->second;
        http_header = curl_slist_append(http_header, headerpara.c_str());
        Log_Mqtt("[CommonOprCurl] [doHttpPostRequest] set CURLOPT_HTTPHEADER, key: {}, value: {}", iter->first, iter->second);
    }
    CURLcode retCI = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_header);
    (void)retCI;
    retCI = curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
    std::string responseBuff;
    retCI = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseBuff);
    retCI = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CommonOprHttp_JSONDataCopy);
    retCI = curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)-1);

    /* Set request timeouts */
    retCI = curl_easy_setopt(curl, CURLOPT_TIMEOUT, 40);
    retCI = curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 100);
    retCI = curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 10);

    retCI = curl_easy_setopt(curl, CURLOPT_URL, (char *)addr.data());
    retCI = curl_easy_setopt(curl, CURLOPT_POST, 0);

    retCI = curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);
    retCI = curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
    retCI = curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);

    string certPath = global_data::g_SdaCaFilePath;
    string rootCertFile = certPath + global_data::g_rootCaCertPem;
    if(!CommonOprSystem::isPathExist(rootCertFile))
    {
        certPath = global_data::g_httpCaFilePath;
        rootCertFile = certPath + global_data::g_rootCaCertPem;
    }
    retCI = curl_easy_setopt(curl, CURLOPT_CAINFO, rootCertFile.c_str());

    string client_cert_path = global_data::g_http_ca_path + global_data::g_client_cert;    
    retCI = curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_MAX_TLSv1_2);
    retCI = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);    
    retCI = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
    retCI = curl_easy_setopt(curl, CURLOPT_SSLCERT, client_cert_path.c_str());
    retCI = curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
    
    // 填充curl_blob结构
    curl_blob private_key_blob = {
        .data = (void *)global_data::g_client_keyBuff.c_str(),
        .len = global_data::g_client_keyBuff.size(),
        .flags = 0};
    // 设置SSL证书的二进制数据
    retCI = curl_easy_setopt(curl, CURLOPT_SSLKEY_BLOB, private_key_blob);

    // 发起请求
    Log_Mqtt("[CommonOprCurl] [doHttpPostRequest] call curl_easy_perform");
    CURLcode res = curl_easy_perform(curl);
    if (res != CURLE_OK)
    {
        Log_Mqtt("[CommonOprCurl] [doHttpPostRequest] Http Error curl response: {}", curl_easy_strerror(res));
    }
    else
    {
        o_resposeBuff = responseBuff;
        //token过期是在成功这里打印提示responseBuff:{"code":46000,"msg":"token错误或过期","success":false} 车端大概间断>3h，再获取token会变化。<3h不会
        Log_Mqtt("[CommonOprCurl] [doHttpPostRequest] Http success");
    }

    // 释放内存
    curl_slist_free_all(http_header);
    curl_easy_cleanup(curl);
    return res == CURLE_OK;
}

bool CommonOprHttp::getCalibrationFile(const string &addr, map<string, string> &http_headermap, string &o_resposeBuff, string &uploadParam, bool withAuthorization, bool isUploadFile)
{
    // 去除json中的换行符，保证云端与车端计算的特征值一致
    CommonOprJson::jsonstrformat(uploadParam);
    Log_Info("[CommonOprHttp] [doHttpPostRequest] postfiled:{}", uploadParam);

    // curl初始化
    CURL *curl = curl_easy_init();
    if (curl == nullptr)
    {
        Log_Mqtt("[CommonOprHttp] [getCalibrationFile] ERROR: curl init failed");
        return false;
    }

    // 设置method为post,设置请求的URL
    CURLcode retCI = curl_easy_setopt(curl, CURLOPT_POST, 1);
    (void)retCI;
    retCI = curl_easy_setopt(curl, CURLOPT_URL, addr.c_str());
    retCI = curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);

    // 设置http请求头
    struct curl_slist *http_header = NULL;
    string headerpara = "";
    map<string, string>::reverse_iterator iter;
    for (iter = http_headermap.rbegin(); iter != http_headermap.rend(); iter++)
    {
        headerpara = iter->first;
        headerpara = headerpara + ":" + iter->second;
        http_header = curl_slist_append(http_header, headerpara.c_str());
        Log_Mqtt("[CommonOprHttp] [getCalibrationFile] set CURLOPT_HTTPHEADER, key: {}, value: {}", iter->first, iter->second);
    }
    // http请求头中生成签名认证信息
    if (withAuthorization)
    {
        headerpara = "Authorization";
        string Authorization = GenAuthorization(STR_REQ_POST, addr, http_headermap, uploadParam);
        headerpara = headerpara + ":" + Authorization;
        http_header = curl_slist_append(http_header, headerpara.c_str());
        Log_Info("[CommonOprCurl] [doHttpPostRequest] header, Authorization:{}", Authorization);
    }

    retCI = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_header);

    std::string responseBuff;

    // 写文件
    std::ofstream calibrationFile;
    std::string filePath = "";
    if (isUploadFile == true)
    {
        // filePath: "/ds/ca_adas/ca_adas_时间.tar.gz"
        uint64_t recordTime = CommonOprTime::getTime();
        std::string calibrationFileTime = CommonOprTime::getDateUTC8str(recordTime);

        filePath = global_data::g_calibration_root_path + global_data::g_calibration_prefix + '_' + calibrationFileTime + '.' + global_data::g_calibration_suffix;
        calibrationFile.open(filePath);
        if (!calibrationFile.is_open())
        {
            Log_Info("[CommonOprHttp][getCalibrationFile] file = {}, open failed", filePath);

            // 释放内存
            curl_slist_free_all(http_header);
            curl_easy_cleanup(curl);
            return 0;
        }

        retCI = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &calibrationFile);
        retCI = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CommonOprHttp_WriteFile);
    }
    else if (isUploadFile == false)
    {
        retCI = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseBuff);
        retCI = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CommonOprHttp_JSONDataCopy);
    }
    retCI = curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)-1);

    /* Set request timeouts */
    retCI = curl_easy_setopt(curl, CURLOPT_TIMEOUT, 40);
    retCI = curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 100);
    retCI = curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 10);

    // 设置密钥验证方式
    retCI = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
    retCI = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
    retCI = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);

    retCI = curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1);
    retCI = curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
    retCI = curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);

    string ca_path = global_data::g_http_ca_path;
    string root_ca_path = global_data::g_rootca_cert;
    string client_cert_path = ca_path + global_data::g_client_cert;
    retCI = curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_MAX_TLSv1_2);
    retCI = curl_easy_setopt(curl, CURLOPT_CAPATH, ca_path.c_str());
    retCI = curl_easy_setopt(curl, CURLOPT_CAINFO, root_ca_path.c_str());
    retCI = curl_easy_setopt(curl, CURLOPT_SSLCERT, client_cert_path.c_str());
    retCI = curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");

    // 设置上传参数
    retCI = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, uploadParam.c_str());
    retCI = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, uploadParam.size());

    // 填充curl_blob结构
    curl_blob private_key_blob = {
        .data = (void *)global_data::g_client_keyBuff.c_str(),
        .len = global_data::g_client_keyBuff.size(),
        .flags = 0};
    // 设置SSL证书的二进制数据
    retCI = curl_easy_setopt(curl, CURLOPT_SSLKEY_BLOB, private_key_blob);

    // 发起请求
    Log_Mqtt("[CommonOprHttp] [getCalibrationFile] call curl_easy_perform");
    CURLcode res = curl_easy_perform(curl);
    if (res != CURLE_OK)
    {
        Log_Mqtt("[CommonOprHttp] [getCalibrationFile] Http Error curl response: {}", curl_easy_strerror(res));
    }
    else
    {
        if (isUploadFile == false)
        {
            o_resposeBuff = responseBuff;
        }
        Log_Mqtt("[CommonOprHttp] [getCalibrationFile] Http success");
    }

    // 释放内存
    curl_slist_free_all(http_header);
    curl_easy_cleanup(curl);

    // 关闭文件
    if (isUploadFile == true)
    {
        calibrationFile.close();
        if (!filePath.empty())
        {
            std::string cmd = "tar -zxvf " + filePath + " -P -C " + global_data::g_tar_calibration_file_path;
            std::system(cmd.c_str());
        }
    }
    return res == CURLE_OK;
}
